package com.augurit.common.base.dao;

import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

/**
 * 在Hibernate事务中执行JDBC的DAO基类
 * 注意事项：
 * 1.JDBC的DAO子类必须与Hibernate的DAO子类使用同一dataSource
 * 2.JDBC的DAO子类必须与Hibernate的DAO子类在同一Spring容器声明Bean
 * 3.Hibernate存在数据缓存，为保证数据可见，要执行“this.getSession().flush();this.getSession().clear();”
 */
public class JdbcSupportInHibernateDao {
	
	protected JdbcTemplate jdbcTemplate;
	protected SimpleJdbcTemplate simpleJdbcTemplate;
	protected TransactionTemplate transactionTemplate;
	

	/**
	 * 根据注入的DataSource创建jdbcTemplate.
	 */
	@Autowired
	public void setDataSource(DataSource dataSource) {
		simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
		jdbcTemplate = new JdbcTemplate(dataSource);
	}

	/**
	 * 根据注入的TransactionManager创建TransactionTemplate
	 */
	@Autowired
	public void setTransactionManager(PlatformTransactionManager transactionManager) {
		transactionTemplate = new TransactionTemplate(transactionManager);
	}
	
	
	public void execute(final String sql){
		transactionTemplate.execute(new TransactionCallbackWithoutResult() {
			@Override
			protected void doInTransactionWithoutResult(TransactionStatus status) {
				jdbcTemplate.execute(sql);
			}
		});
	}
	
	public Integer[] batchUpdate(final String sql, final List<Object[]> batchArgs){
		return (Integer[])transactionTemplate.execute(new TransactionCallback() {
			public Object doInTransaction(TransactionStatus status) {
				return simpleJdbcTemplate.batchUpdate(sql, batchArgs);
			}
		});
	}
	
	public Integer update(final String sql, final Object... args){
		return (Integer)transactionTemplate.execute(new TransactionCallback() {
			public Object doInTransaction(TransactionStatus status) {
				return simpleJdbcTemplate.update(sql, args);
			}
		});
	}
	
	public Integer update(final String sql, final SqlParameterSource args){
		return (Integer)transactionTemplate.execute(new TransactionCallback() {
			public Object doInTransaction(TransactionStatus status) {
				return simpleJdbcTemplate.update(sql, args);
			}
		});
	}
	
	public Integer update(final String sql, final Map<String, ?> args){
		return (Integer)transactionTemplate.execute(new TransactionCallback() {
			public Object doInTransaction(TransactionStatus status) {
				return simpleJdbcTemplate.update(sql, args);
			}
		});
	}
	
	public <T> T queryForObject(final String sql, final Class<T> requiredType, final Object... args){
		return (T) transactionTemplate.execute(new TransactionCallback() {
			public Object doInTransaction(TransactionStatus status) {
				return simpleJdbcTemplate.queryForObject(sql, requiredType, args);
			}
		});
	}
	
	public <T> T queryForObject(final String sql, final Class<T> requiredType, final Map<String, ?> args){
		return (T) transactionTemplate.execute(new TransactionCallback() {
			public Object doInTransaction(TransactionStatus status) {
				return simpleJdbcTemplate.queryForObject(sql, requiredType, args);
			}
		});
	}
}
